#ifndef _PLAYER_H_
#define _PLAYER_H_

#include "medved/manager.hpp"

short unitsToVelocity(short units);
short unitsToEnergy(short units);

enum
{
	PLAYER_DEFAULT_ENERGY = 1500,
	PLAYER_DEFAULT_MAX_ENERGY = 3000,
	PLAYER_DEFAULT_DURABILITY = 1500,
	PLAYER_DEFAULT_MAX_VELOCITY = 8,
	PLAYER_DEFAULT_VISUAL_SECTOR = 15,
	PLAYER_DEFAULT_SHOOT_SECTOR = 10,
	PLAYER_DEFAULT_MAX_FIRE = 50,
	PLAYER_SHOOT_COOLDOWN = 5,
	SWAMP_MAX_VELOCITY = 4,
	SWAMP_VISCOSITY_FACTOR = 10
};

template <class T>
inline T abs(T a)
{
	return a > 0 ? a : -a;
}

short vectorModulo(short x, short y);

struct Player
{
	enum
	{
		COORDINATE_SCALE = 120
	};
	short x, y;
	
	// velocity units are conventional (scaled)
	short velx, vely;

	short xAccum, yAccum;
	short energy;
	short maxEnergy;
	short maxVelocity;
	short maxFire;
	short durability;
	short visualSector, shootSector;
	short shootCooldown;
	bool isAlive;

	// hack hack hack ???
	// explicit dependency between Player and Swamp classes
	// seems to be redudnant, but other solutions i could offer are awful
	bool isInSwamp;

	Player() :
		velx(0), vely(0), xAccum(0), yAccum(0),
		energy(PLAYER_DEFAULT_ENERGY), maxEnergy(PLAYER_DEFAULT_MAX_ENERGY),
		maxVelocity(PLAYER_DEFAULT_MAX_VELOCITY), maxFire(PLAYER_DEFAULT_MAX_FIRE), 
		durability(PLAYER_DEFAULT_DURABILITY),
		visualSector(PLAYER_DEFAULT_VISUAL_SECTOR), shootSector(PLAYER_DEFAULT_SHOOT_SECTOR),
		shootCooldown(0), isAlive(true), isInSwamp(false)
	{}

	bool adjustVelocity(short x, short y);
	bool adjustDurability(short value);
	void adjustEnergy(short value);
	void brake();
	short velocityModulo() const { return vectorModulo(velx, vely); }
	inline short getMaxVelocity() const { return isInSwamp ? static_cast<short>(SWAMP_MAX_VELOCITY) : maxVelocity; }
	bool isCouldShoot(short tx, short ty);

	void kill() { isAlive = false; }
	
	template <class T>
	void traverseMembers(const T &d)
	{
		d & x & y & velx & vely & xAccum & yAccum &
			energy & maxEnergy & maxVelocity & maxFire & durability &
			visualSector & shootSector & shootCooldown & isAlive & isInSwamp;
	}

};

struct ManagedPlayer : public Player, public Medved::Managed
{
	ManagedPlayer() :
		Player(), Medved::Managed()
	{}
};

#endif
